/*-------------------------------------------------------------------------------
* file:     app_clk_adj.c
* brief:    application
* copyright Copyright (C) 2020-2022 @ NanoIC
* Date:     2022-08-15
* Version:  V1.00
* Author:   
*-------------------------------------------------------------------------------*/


/* include ----------------------------------------------------------------*/
#include "app_init.h"
#include "app_timer.h"
#include "app_iic.h"
#include "pin.h"
#include "tick.h"
#include <drv/iwdt.h>
#include "app_manufacture.h"
#include "app_clk_adj.h"

uint32_t lpt_irq_num;
uint32_t sys_core_tick_statr,sys_core_tick_end_500mS,sys_core_tick_end_1000mS;
uint32_t sys_core_tick_err_num,sys_core_tick_err_dif;

uint32_t  deb_time_dif[100][2];
uint8_t   deb_time_index;
/**
 * @brief : 上电初始化时钟校准函数
 */
void app_clk_adj_init(bool f_power_on)
{
    csi_error_t status;

    lpt_irq_num = 0x00;
    sys_core_tick_statr = 0x00;
    sys_core_tick_end_500mS = 0x00;
    sys_core_tick_end_1000mS = 0x00;
    sys_core_tick_err_num = 0x00;
    sys_core_tick_err_dif = 0x00;
    /*
     * 初始化lpt,选用内部超低功耗时钟,定时100ms,默认采用PEND中断
     */
    status = csi_lpt_timer_init(LPT,LPT_CLK_ISCLK, 100);
    if(status == CSI_OK)
    {
        csi_lpt_start(LPT);  // 启动lpt
    }

    deb_time_index = 0x00;
    for(uint8_t i =0;i<100;i++)
    {
        deb_time_dif[i][0] = 0x00;
        deb_time_dif[i][1] = 0x00;
    }
}

#if (APP_DEBUG_PIN_ENABLE == 1)
    uint8_t  lpt_pin_lev = 0;
#endif
/**
 * @brief : 低功耗定时器，PEND中断回调
 */
void app_lpt_pend_irq_callback(void)
{
    uint32_t irq;
    lpt_irq_num ++;
    if(lpt_irq_num > 50)
    {   // 5秒校准一次频率
        lpt_irq_num = 0;
    }
    if(lpt_irq_num == 1)
    {  // 记录Timer值(100mS)
        irq = csi_irq_save();
        sys_core_tick_statr = csi_tick_get_us();
        csi_irq_restore(irq);
    }else if(lpt_irq_num == 6)
    {  // 记录Timer值，停止Timer，并计算时钟精度，并校准RC(600mS)
        irq = csi_irq_save();
        sys_core_tick_end_500mS = csi_tick_get_us();
        csi_irq_restore(irq);
    }else if(lpt_irq_num == 11)
    {  // 记录Timer值，停止Timer，并计算时钟精度，并校准RC(600mS)
        irq = csi_irq_save();
        sys_core_tick_end_1000mS = csi_tick_get_us();
        csi_irq_restore(irq);
        if((sys_core_tick_end_500mS > sys_core_tick_statr) && (sys_core_tick_end_1000mS > sys_core_tick_statr))
        {
            uint32_t time_expend_one,time_expend_two;
            time_expend_one = sys_core_tick_end_500mS - sys_core_tick_statr;
            time_expend_two = sys_core_tick_end_1000mS - sys_core_tick_end_500mS;
            if((time_expend_one > 450000) 
                && (time_expend_one < 550000) 
                && (time_expend_two > 450000)
                && (time_expend_two < 550000)
                )
            {
                app_sys_clk_calibration(time_expend_one,time_expend_two);
            }else{
                sys_core_tick_err_num ++;
            }
        }
    }

#if (APP_DEBUG_PIN_ENABLE == 1)
    if(lpt_pin_lev & 0x01)
    {
        app_debug_pin_set(0xff,1);
    }else{
        app_debug_pin_set(0xff,0);
    }
    lpt_pin_lev ++;
#endif
}

/**
 * @brief : 系统内部时钟校准
 */
void app_sys_clk_calibration(uint32_t time_diff,uint32_t time_diff_dub)
{
    uint32_t val;

    if(time_diff >= time_diff_dub)
    {
        val = time_diff - time_diff_dub;
    }else{
        val = time_diff_dub - time_diff;        
    }
    if(val <= 2000)
    {  // 两次测量出来的结果，对比偏差千分之四内，调整RC
        app_sys_rc_adjust(time_diff_dub);
    }else{
        sys_core_tick_err_dif++;
    }



    
    if(deb_time_index < 100)
    {
        deb_time_dif[deb_time_index][0] = time_diff;
        deb_time_dif[deb_time_index][1] = time_diff_dub;
        deb_time_index ++;
    }

}
uint32_t reg_syscon_clcr,hfo_tune,clcr_adj_val;
/**
 * @brief : 系统内部RC调整
 */
void app_sys_rc_adjust(uint32_t time_diff)
{
    uint32_t error,irq;
    if(time_diff > 500000)
    {
        error = time_diff - 500000;
    }else{
        error = 500000 - time_diff;
    }
    error /= 500;  // 1% : 16
    clcr_adj_val = error * 3;  // 3/4 = 0.75
    clcr_adj_val /= 4;
    if(clcr_adj_val > 48)
    {   // 单次最大调节3%左右
        clcr_adj_val = 48;
    }

    if((error > 20) && (error < 100))
    {  // 1% ~ 10%之间校准
        irq = csi_irq_save();
        reg_syscon_clcr = SYSCON->CLCR;
        hfo_tune = reg_syscon_clcr & 0x1ff;
        reg_syscon_clcr &= 0xfffffe00;

        if(time_diff > 500000)
        {
            if(hfo_tune > clcr_adj_val)
            {
                hfo_tune -= clcr_adj_val;
            }
        }else{
            if((hfo_tune + clcr_adj_val) < 255)
            {
                hfo_tune += clcr_adj_val;
            }
        }

        if(hfo_tune > 304)  // 0xF0(240) + 64 = 304
        {  // 总最大调节范围
            hfo_tune = 304;
        }
        if(hfo_tune  < 176) // 240 - 64 = 176
        {  // 总最小调节范围
            hfo_tune = 176;
        }
        SYSCON->CLCR = reg_syscon_clcr | hfo_tune;
        csi_irq_restore(irq);
    }
}